#ifndef FEATURESEXTRACTOR_H
#define FEATURESEXTRACTOR_H

#include "SegmentedObject.h"
#include "Transformations.h"
#include <cmath>
#include <QPoint>
#include <QList>



class FeaturesExtractor
{

public:
    /**
      * Returns the object's perimeter, in pixel units
      *
      * @param object is the segmented object to be analysed
      */
    static int perimeter(SegmentedObject* object)
    {
        // As indicates here, http://web.cecs.pdx.edu/~mperkows/CAPSTONES/2005/L001.computerVision.pdf
        // perimeter is the amount of pixels in the blob that borders a "0"


        QSet<int> * pixels = object->getSegmentedObject();

        int pixel;
        int perimeter = 0;

        bool isPerimeter;

        // For each pixel
        foreach(pixel, *pixels)
        {
            // Let's suppose that the pixel isn't included in the perimeter
            isPerimeter = false;

            int pX = Transformations::getX(object->getSegmentation()->getImage(), pixel);
            int pY = Transformations::getY(object->getSegmentation()->getImage(), pixel);

            // List of pixels to visit
            QList< QPoint > pixelsToVisit;
            pixelsToVisit << QPoint(pX, pY - 1) << QPoint(pX, pY + 1) << QPoint(pX - 1, pY) << QPoint(pX + 1, pY);

            QPoint neighbor;

            foreach (neighbor, pixelsToVisit)
                {
                 //   int j = neighbor.x(); int i = neighbor.y();
                    QImage * img = object->getSegmentation()->getImage();

                    // If it is not the center pixel...
                    if (Transformations::getPixelNumber(img, neighbor.x(), neighbor.y()) != pixel)
                        // Checking if the pixel is included into the Image...
                        if (img->rect().contains(neighbor.x(), neighbor.y()))
                            // If the pixel is contained in the blob...
                            if (!pixels->contains(Transformations::getPixelNumber(img, neighbor.x(), neighbor.y())))
                                isPerimeter = true;
                }

            if (isPerimeter)
                perimeter++;
        }

        return perimeter;
    }

    /**
      * Returns the object's circularity index, which indicates how alike the object shape is with a circle.
      *
      * @param object is the segmented object to be analysed
      */
    static float circularityIndex(SegmentedObject* object)
    {

        //get the area of the object
        int area = FeaturesExtractor::area(object);
        //get the perimeter of the object
        int perimeter = FeaturesExtractor::perimeter(object);

        //   IC = A/B, where IC is the circularity index,A is the object area and B is the area of the equivalent circle.
        //   B = PI * r², where r is the circle's ratio.
        //   p = 2*Pi*r, where p is the perimeter of the object.
        //   Then r = p / (2*Pi).
        //   Then B = (p²) / (4*PI)

        //Then the circularity index is

        double pi = 4 * std::atan(1);

        float circularityIndex = ( 4 * pi * area ) / ( perimeter^2 );

        return circularityIndex;
    }

    /**
      * Returns the object's area, in pixel units
      *
      * @param object is the segmented object to be analysed
      */

    static int area(SegmentedObject* object)
    {
        QSet<int> * pixels = object->getSegmentedObject();
        return pixels->size();
    }

    /**
      * Returns the object's gravity center, by means of calculating the average X coordinate
      * and Y coordinate
      *
      * @param object is the segmented object to be analysed
      */

    static QPoint gravityCenter(SegmentedObject* object)
    {
        QSet<int> * pixels = object->getSegmentedObject();

        //I asume I got the following method
        QImage * image = object->getSegmentation()->getImage();

        // this variable contains the pixel in every cycle
        int i;

        //this variables contains the X and Y coordinates in every cycle
        int x,y;

        //this variables contains the average X and Y, being actualized in every cycle.
        int avgx = 0;
        int avgy = 0;

        foreach(i,*pixels)
        {
          //Obtained the X and Y coordinate corresponding to the pixel in this cycle
          x = Transformations::getX(image,i);
          y = Transformations::getY(image,i);

          //Actualized the average X and Y
          avgx += x;
          avgy += y;
        }

        //Calculated the real average X and Y
        avgx /= pixels->size();
        avgy /= pixels->size();

        QPoint center(avgx,avgy);

        //returned the point in which is located the gravity center
        return center;

        }

};



#endif // FEATURESEXTRACTOR_H
